from djcontrol import *

from Tkinter import *
import djcontrolutil

from Djoser.tkwrappers.scrolledlistbox import ScrolledListbox

class DjListbox(DjControl):
	"""
	Listbox widget. Pass in scrollbar=True to add a scrollbar.
	
	
	Properties:
	
	*scrollbar* - True or false. Display a vertical scrollbar. Can only be set when the control is first created, in the constructor.
	*items* - List of strings. Each string will be an item in the listbox.
	*multiple* - If True, users can use Shift or Control to select ranges of items.
	*enabled* - If False, the listbox is grayed out.
	
	*bgcolor* - Background color of the listbox. RGB triplet, such as (255,0,0) for pure red.
	*color* - Foreground color of the listbox. RGB triplet.
	*borderwidth* - An integer, width of border in pixels.
	*borderstyle* - Border style. One of 'sunken','raised','groove','ridge','flat'. Default is 'sunken'.
	*selectioncolor* - Color of text when an item is selected. RGB triplet.
	*selectionbgcolor* - Background color when an item is selected. RGB triplet.
	
	*width* - Set width of listbox, where one unit is the width of a char. Defaults to 20.
	*height* - Set height of listbox, how many items are displayed. Defaults to 10.
	*font* - Set font of items in the listbox. Standard tkinter font format, such as ('Times New Roman', 12, 'normal')
	
	*ondoubleclick* - Set a callback for when an item is double-clicked. Callback function should take one argument, the selected items.
	"""
	
	# Note that only names beginning with '_', or the special case basecontrol, should be used.
	_autoProperties = None
	_scrollbar = False
	_ondoubleclick = None
	basecontrol = 0
	
	def __init__(self, parent, scrollbar=False, **options):
		parent = djcontrolutil.getbasecontrol(parent)
		if scrollbar:
			self.basecontrol = ScrolledListbox(parent)
			self._scrollbar = True
		else:
			self.basecontrol = Listbox(parent)
		# If there are multiple listboxes in the same window, you might want to .configure(exportselection=0)
		self.basecontrol.config(exportselection=0)
		
		self._autoProperties = { 
		# Property name,  Tkinter property name, SET wrapper, GET wrapper
		'multiple':('selectmode', _boolToSelectmode, _selectmodeToBool),
		'enabled':('state', _boolToState, _stateToBool),
		'bgcolor': ('background',djcontrolutil.colorToString,djcontrolutil.stringToColor),
		'color': ('foreground',djcontrolutil.colorToString,djcontrolutil.stringToColor),
		'selectioncolor': ('selectforeground',djcontrolutil.colorToString,djcontrolutil.stringToColor),
		'selectionbgcolor': ('selectbackground',djcontrolutil.colorToString,djcontrolutil.stringToColor),
		
		'borderwidth': ('borderwidth',None,None),
		'borderstyle': ('relief', djcontrolutil.stringToRelief,djcontrolutil.reliefToString),
			
		'width': ('width',None,None),
		'height': ('height',None,None),
		'font': ('font',None,None),
		}
		self.set_many(**options)
	
	
	def add_item(self, entry, bEnd=False):
		"""Append item to the current location, or to the end if bEnd is True."""
		if bEnd:
			self.basecontrol.insert(END, entry)
		else:
			self.basecontrol.insert(ACTIVE, entry)
		
	def insert_item(self, index, entry):
		"""Insert item at the given index."""
		self.basecontrol.insert(index, entry)
	
	def delete_item(self, index):
		"""Delete item at the given index."""
		self.basecontrol.delete(index)
	
	def style_item(self, index, **options):
		"""Style one item of the list, at the given index. background='blue', foreground='#0000ff', font, and so on."""
		self.basecontrol.itemconfig(index, **options)
		
	def style_item_get(self, index, option):
		"""Retrieve style information for one item of the list. background='blue', foreground='#0000ff', font, and so on."""
		return self.basecontrol.itemcget(index, option)	
	
	def clear(self):
		"""Clear all items."""
		self.basecontrol.delete(0,END)
	
	def get_selected_items(self):
		"""Returns list of strings, which represent the selected items. Returns empty list if there is no selection."""
		ret = []
		for index in self.get_selection():
			ret.append(self.basecontrol.get(index))
		return ret
	
	def get_selection(self):
		"""Returns list of integers, the indices of selected items. Returns empty list if there is no selection."""
		if len(self.basecontrol.curselection())==0:
			return []
		else:
			return map(int, self.basecontrol.curselection())
			
	def deselect(self):
		"""Deselect all items."""
		self.basecontrol.selection_clear(0,END)
		
	def set_selection(self,index):
		"""Select the item at the given index"""
		# If we aren't on select multiple, clear the selection first.
		if not self.multiple: self.deselect()
		self.basecontrol.selection_set(index)
	
	def scrollto_start(self):
		"""Scroll to start."""
		self.basecontrol.see(0)
		
	def scrollto_end(self):
		"""Scroll to end."""
		self.basecontrol.see(END)
	
	_customProperties = ('items','scrollbar','ondoubleclick')
	def _lookupCustomProperties(self, bSet, strAttribute, value=None):
		if strAttribute=='items':
			if bSet:
				self.basecontrol.delete(0,END)
				for item in value:
					self.basecontrol.insert(END, item)
				self.basecontrol.update_idletasks()
			else:
				return self.basecontrol.get(0,END)
		elif strAttribute=='scrollbar':
			if bSet: raise RuntimeError, 'Property can only be set when the field is first created, in the constructor.'
			else: return self._scrollbar
		elif strAttribute=='ondoubleclick':
			if bSet:
				# Assumes value is a function taking one argument.
				fn = lambda event: value(self.get_selected_items())
				self.basecontrol.bind("<Double-Button-1>", fn)
				self._ondoubleclick = fn
			else:
				return self._ondoubleclick
		
		
def _boolToSelectmode(b):
	if b: return EXTENDED
	else: return BROWSE
def _selectmodeToBool(state):
	if state==EXTENDED or state==MULTIPLE: return True
	else: return False

def _boolToState(b):
	if b: return NORMAL
	else: return DISABLED
def _stateToBool(state):
	if state==DISABLED: return False
	else: return True


